# coding=utf-8
"""
copyright (c) 2009, paketka@gmail.com et. al
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.

    * Neither the name of the <ORGANIZATION> nor the names of its contributors
      may be used to endorse or promote products derived from this software
      without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
import datetime
from GChartWrapper import *

from django.utils.translation import ugettext as _

def create_pie(data):
    """
    uses data to create a chart. data is a dictionary: values in dictionary are
    values, while keys are value names.

    Example:
        {   'women' : 20,
            'man' : 80,
        }
    will create 20/80 chart with description to each value

    """

    retVal = Pie3D(data.values())

    args = []
    total = reduce(lambda x, y: x + y, data.values()) * 1.0
    args = map(lambda x: '%s %.2f%%' % (x, ((data[x] / total) * 100)),
                    data.keys()
            )
    retVal.label(*args)

    ###
    # TODO: colors must be gathered from group.
    colors = []
    colorStart = 0x55
    color = 0x55
    formatStrs = ['0000%x', '00%x00', '%x0000']
    for i in range(len(data)):
        if i % 3 == 0:
            colorStart += 0x11
            color = colorStart

        colors.append(formatStrs[i % 3] % color)

    retVal.color(*colors) 

    return retVal
    

def get_year_rng_axes(terms):
    """
    gets string parameters for x graph axis.  it's mainly used for vertical bar
    chart, which describes comparison between office terms.
    
    these year ranges appears as two rows of values.
        start years (startY)
        end years (endY)
    below corresponding bar
    """
    startY = ''
    endY = ''
    for t in terms:
        startY += t.yearStart + '|'
        if t.yearEnd == '':
            endY += str(datetime.datetime.today().year)
        else:
            endY += t.yearEnd + '|'
    
    return startY, endY


def get_axis(r, spaces = 0, offset = 0):
    """
    creates an axis for a graph:
        r - values to be placed to axis
        spaces - number of spaces (empty rows/cols) between values
        offset - offset to move from beginning (nmber of empty rows/cols)
    """
    retVal = u''
    for i in range(offset):
        retVal += u' |'

    for i in r:
        retVal += unicode(i) + u'|'

        for j in range(spaces):
            retVal += u' |'

    return retVal

    
def make_title(title, desiredLineLen):
    """
    title is string, blockLen is approx length in chars we want to fit in
    """
    lineLen = 0
    retVal = u''
    for word in title.split(): 
        lineLen += len(word)
        retVal += word + u' '
        
        if lineLen > desiredLineLen:
            retVal += '\n'
            lineLen = 0

    return retVal



def get_percents(part, total):
    """
    Returns amount of part in percents. Percents are rounded to two dec. fields.
    Returns float.
    """
    if total == 0:
        total = 1

    return (((1.0 * part) / total) * 100.0)


class Votes(object):
    """
    This is a vote stat class. It's used to accumulate poll statistics for any period.
    It can be used either for MP or group of MPs.
    """
    votesAye = 0
    votesNay = 0
    votesRefrain = 0
    absences = 0
    excused = 0
    _totalVotes = 0
    _totalAbsences = 0
    startDate = None
    endDate = None

    def __init__(   self,
                    vAye = 0,
                    vNay = 0,
                    vRefrains = 0,
                    absences = 0,
                    excused = 0,
                    sDate = None,
                    eDate = None
                ):
        """
        Constructor has following parameters:
            vAye        - total number of votes Aye
            vNay        - total number of votes Nay
            vRefrains   - total number of refrains
            absencs     - total number of absences
            excsd       - total number of excused absences
            sDate       - start date for given stat
            eDate       - end date of period
        all parameters are optional
        """
        if vAye == None:
            self.votesAye = 0
        else:
            self.votesAye = vAye

        if vNay == None:
            self.votesNay = 0
        else:
            self.votesNay = vNay

        if vRefrains == None:
            self.votesRefrain = 0
        else:
            self.votesRefrain = vRefrains

        if excused == None:
            self.excused = 0
        else:
            self.excused = excused

        if absences == None:
            self.absences = 0
        else:
            self.absences = absences

        self.startDate = sDate
        self.endDate = eDate
        return


    @property
    def presence(self):
        return self.votesAye + self.votesNay + self.votesRefrain


    @property
    def totalAbsences(self):
        if self._totalAbsences == 0:
            self._totalAbsences = self.absences + self.excused
        return self._totalAbsences


    @property
    def totalVotes(self):
        if self._totalVotes == 0:
            self._totalVotes = self.votesAye + self.votesNay +\
                self.votesRefrain + self.absences + self.excused
        return self._totalVotes


    @property
    def ayesPerc(self):
        return get_percents(self.votesAye, self.totalVotes)


    @property
    def naysPerc(self):
        return get_percents(self.votesNay, self.totalVotes)
    

    @property
    def refrainsPerc(self):
        return get_percents(self.votesRefrain, self.totalVotes)


    @property
    def absencesPerc(self):
        return get_percents(self.absences, self.totalVotes)
        

    @property
    def excusedPerc(self):
        return get_percents(self.excused, self.totalVotes)


    @property
    def totalAbsencesPerc(self):
        return get_percents(self.totalAbsences, self.totalVotes)


    @property
    def presencePerc(self):
        return get_percents(self.presence, self.totalVotes)


    def getVotesChart(self, group = False):
        """
        Returns an instance to Pie3D object. The pie chart is compund of all 5
        portions:
            aye
            nay
            refrain
            absences
            excused

        optional parameter group - the chart is returned with labels for group,
        otherwise for person (default)

        if chart is for group then there will just four portions, since there is
        no meaning to calculate excused absences for group of MPs.
        """
        retVal = None
        if group:
            retVal = Pie3D([    self.ayesPerc, self.naysPerc,
                                self.refrainsPerc, self.absencesPerc, 
                        ])
            retVal.label(
                _(u'Pro %.2f %%') % self.ayesPerc,
                _(u'Proti %.2f %%') % self.naysPerc,
                _(u'Zdrželo %.2f %%') % self.refrainsPerc,
                _(u'Chybělo %.2f %%') % self.totalAbsencesPerc,
            )
            retVal.color('007700', '770000', '777777', '000000')
        else:
            retVal = Pie3D([    self.ayesPerc, self.naysPerc, self.refrainsPerc,
                                self.excusedPerc, self.absencesPerc
                        ])
            retVal.label(
                _(u'Pro %.2f %%') % self.ayesPerc,
                _(u'Proti %.2f %%') % self.naysPerc,
                _(u'Zdržel %.2f %%') % self.refrainsPerc,
                _(u'Omluven %.2f %%') % self.excusedPerc,
                _(u'Chybí %.2f %%') % self.absencesPerc
            )
            retVal.color('007700', '770000', '777777', '007777', '000000')

        return retVal


    def getPresenceChart(self, group = False):
        """
        Returns an instance of Pie3D object. Pie object is compound of three
        portions:
            presences
            excused absences
            absences

        optional parameter group - the chart is returned with labels for group,
        otherwise for person (default)

        if chart is for group the portions will be just three, since there is
        no meaning to calculate excused absences for group of MPs.
        """
        retVal = None
        if group:
            retVal = Pie3D([    100.0 - self.totalAbsencesPerc,
                                self.totalAbsencesPerc
                        ])
            retVal.label(
                _(u'Přítomno %.2f %%') % 100.0 - self.totalAbsencesPerc,
                _(u'Chybí %.2f %%')  % self.totalAbsencesPerc
            )
            retVal.color('007700', '770000')
        else:
            retVal = Pie3D([    100.0 - self.totalAbsencesPerc, self.excusedPerc,
                                self.absencesPerc
                        ])
            retVal.label(
                _(u'Účast %.2f %%') % (100.0 - self.totalAbsencesPerc),
                _(u'Omluveno %.2f %%') % self.excusedPerc,
                _(u'Chybí %.2f %%') % self.absencesPerc
            )
            retVal.color('007700', '774400', '770000')


        return retVal


class Accordance(object):
    """
    Encapsulates poll accordance of two entities (either group/person, group/group)
    The method getChart() returns instance of Pie3D class, which prestns the ratio
    between same and different polls.
    """
    same = 0
    diff = 0
    _totalVotes = 0
    startDate = None
    endDate = None

    def __init__(   self,
                    same = 0,
                    diff = 0,
                    sDate = None,
                    eDate = None
            ):
        self.same = same
        self.diff = diff
        self.startDate = sDate
        self.endDate = eDate
        return


    @property
    def totalVotes(self):
        if self._totalVotes == 0:
            self._totalVotes = self.same + self.diff
        return self._totalVotes


    @property
    def diffPerc(self):
        return get_percents(self.diff, self.totalVotes)


    @property
    def samePerc(self):
        return get_percents(self.same, self.totalVotes)


    def getChart(self):
        retVal = Pie3D([ self.samePerc, self.diffPerc ])
        retVal.label(
            _(u'Stejně %.2f %%') % self.samePerc,
            _(u'Jinak %.2f %%') % self.diffPerc
        )
        retVal.color('007700', '770000')
        return retVal
